﻿
#include "CenterDuplicateMgr.h"
#include "Active/ActiveCharacterMgr.h"
#include "Cache/OfflineCharacterDataMgr.h"
#include "Common/TableData/DuplicateDuplicateCfg.h"
#include "CenterService.h"
#include "Common/Utility/ServerTime.h"
#include "Room/RoomMgr.h"
#include "SceneMgr/CenterSceneMrg.h"
#include "Team/TeamManager.h"
#include "Common/TableDataEx/DuplicateCfg.h"
#include "Union/UnionMgr.h"
#include "ActivityMgr/ActivityMgr.h"
#include "AccountMgr/CenterAccountMgr.h"
#include "Script/ScriptMgr_CS.h"
#include "Common/TableDataEx/TeleportCfg.h"
#include "Character/monster/MonsterRefCfg.h"
#include "Common/TableDataEx/MapCfg.h"
#include "Common/TableData/TeleportBornCfg.h"

CenterDuplicateMgr::CenterDuplicateMgr()
{
	m_mapDupData.clear();
	m_mapWaitDupData.clear();
	m_mapWaitCreate.clear();
	m_mapDupChar.clear();
	m_charEnterArea.clear();
	m_mapWaitRet.clear();
	m_pDupTeamStatePool = nullptr;
	m_mapQueue.clear();
	m_queueUID = 0;
	m_mapWaitCreateUnion.clear();
	m_vecGuideCfg.clear();
}

CenterDuplicateMgr::~CenterDuplicateMgr()
{

}

bool CenterDuplicateMgr::Init()
{
	if (!LoadGuideStepCfg())
	{
		return false;
	}
	m_mapDupData.clear();
	m_mapWaitDupData.clear();
	m_mapWaitCreate.clear();
	m_mapDupChar.clear();
	m_charEnterArea.clear();
	m_mapWaitRet.clear();
	m_teamState.clear();
	m_mapQueue.clear();
	m_mapWaitCreateUnion.clear();
	m_queueUID = 0;
	m_pDupTeamStatePool = new ObjectPool<DupTeamState>(20, false);
	MMO_ASSERT(nullptr != m_pDupTeamStatePool);
	m_pDupQueuePool = new ObjectPool<DupQueue>(20, false);
	MMO_ASSERT(nullptr != m_pDupQueuePool);

	g_GetTimerAxis()->SetTimer(ETimer_ID_Check_Queue, 2 * 1000, this);
	

	return true;
}

void CenterDuplicateMgr::UnInit()
{
	g_GetTimerAxis()->KillAllTimer(this);
	g_GetTimerAxis()->KillAllFixTimer(this);
	m_mapDupData.clear();
	m_mapWaitDupData.clear();
	m_mapWaitCreate.clear();
	m_mapDupChar.clear();
	m_charEnterArea.clear();
	m_mapWaitRet.clear();
	m_vecGuideCfg.clear();

	DupTeamStateMap::iterator iter = m_teamState.begin();
	for (; iter != m_teamState.end(); ++iter)
	{
		DupTeamState *teamState = iter->second;
		if (nullptr != teamState)
		{
			teamState->uninit();
			FreeTeamStateObj(teamState);
		}
	}
	m_teamState.clear();


	DupQueueMap::iterator iterQueue = m_mapQueue.begin();
	for (; iterQueue != m_mapQueue.end(); ++iterQueue)
	{
		DupQueue *pQueue = iterQueue->second;
		if (nullptr != pQueue)
		{
			pQueue->UnInit();
			FreeQueueObj(pQueue);		
		}
	}
	m_mapQueue.clear();


	MMO_DELETE(m_pDupTeamStatePool);
	MMO_DELETE(m_pDupQueuePool);
	//
	m_queueUID = 0;
}


DupTeamState *CenterDuplicateMgr::MakeTeamStateObj()
{
	if (nullptr != m_pDupTeamStatePool)
	{
		return m_pDupTeamStatePool->MallocObj();
	}
	return nullptr;
}

void CenterDuplicateMgr::FreeTeamStateObj(DupTeamState *pObj)
{
	if (nullptr != pObj)
	{
		m_pDupTeamStatePool->FreeObj(pObj);
	}
}

void CenterDuplicateMgr::RecycleTeamState(DupTeamState *pTeamState)
{
	if (nullptr != pTeamState)
	{
		uint32_t teamId = pTeamState->teamId();
		DupTeamStateMap::iterator iter = m_teamState.find(teamId);
		if (iter != m_teamState.end())
		{
			m_teamState.erase(iter);
		}
		pTeamState->uninit();
		//
		FreeTeamStateObj(pTeamState);
	}
}

DupQueue *CenterDuplicateMgr::CreateQueue()
{
	int32_t queueId = NewQueueId();
	DupQueue *pQueue = MakeQueueObj();
	if (nullptr != pQueue)
	{
		pQueue->Init(queueId);
		m_mapQueue[queueId] = pQueue;
	}
	return pQueue;
}

DupQueue *CenterDuplicateMgr::MakeQueueObj()
{
	if (nullptr != m_pDupQueuePool)
	{
		return m_pDupQueuePool->MallocObj();
	}
	return nullptr;
}

void CenterDuplicateMgr::FreeQueueObj(DupQueue *pObj)
{
	if (nullptr != pObj)
	{
		m_pDupQueuePool->FreeObj(pObj);
	}
}

void CenterDuplicateMgr::RecycleQueue(DupQueue *pQueue)
{
	if (nullptr != pQueue)
	{
		int32_t queueId = pQueue->QueueId();
		DupQueueMap::iterator iter = m_mapQueue.find(queueId);
		if (iter != m_mapQueue.end())
		{
			m_mapQueue.erase(iter);
		}
		pQueue->UnInit();
		FreeQueueObj(pQueue);
	}
}

void CenterDuplicateMgr::LogicCrash(uint32_t logicId)
{
	//清除等待逻辑服创建副本结果返回的记录，避免玩家无法进副本
	SET_UINT32 setWaitScene;
	setWaitScene.clear();
	DupDataMap::iterator iter = m_mapWaitDupData.begin();
	while (iter != m_mapWaitDupData.end())
	{
		dupInfo &info = iter->second;
		if (logicId != info.logicServerId)
		{
			++iter;
			continue;
		}
		setWaitScene.insert(info.sceneId);
		LogInfoFmtPrint("[center] CenterDuplicateMgr::LogicCrash...wait create duplicate....logicid:%u, dupid:%u,sceneid:%u, cid:%lu,keytype:%d,keyvalue:%lu,union_sceneType:%d ", logicId, info.dupId,info.sceneId, info.cid, info.keyType, info.keyValue, info.unionSceneType);
		++iter;
	}
	SET_UINT32::iterator iterClear = setWaitScene.begin();
	for (; iterClear != setWaitScene.end(); ++iterClear)
	{
		delWaitDuplicate((*iterClear), RET_FAIL);
	}

	//逻辑服创建副本结果已经返回并且成功的，需要清除等待玩家进入副本的标记
	SET_UINT32 setWaitRet;
	setWaitRet.clear();
	DupWaitRetMap::iterator iterRet = m_mapWaitRet.begin();
	for (; iterRet != m_mapWaitRet.end(); ++iterRet)
	{
		CharIDType charId = iterRet->first;
		dupWaitRet &waitRet = iterRet->second;
		if (logicId == dupSceneLogic(waitRet.sceneId))
		{
			setWaitRet.insert(charId);
		}
	}
	SET_UINT32::iterator iterDel = setWaitRet.begin();
	for (; iterDel != setWaitRet.end(); ++iterDel)
	{
		delDupWaitRet((*iterDel));
	}

	//删除中心服副本记录
	SET_UINT32 setDelDup;
	setDelDup.clear();
	MAP_UINT32_SET_INT32 mapUnionScene;
	mapUnionScene.clear();
	DupDataMap::iterator iterDup = m_mapDupData.begin();
	for (; iterDup != m_mapDupData.end(); ++iterDup)
	{
		dupInfo &info = iterDup->second;
		if (logicId != info.logicServerId)
		{
			continue;
		}
		if (EDuplicateKeyType_Union == info.keyType) //工会驻地场景
		{
			uint32_t unionId = (uint32_t)info.keyValue;
			MAP_UINT32_SET_INT32::iterator iterUnion = mapUnionScene.find(unionId);
			if (iterUnion != mapUnionScene.end())
			{
				SET_INT32 &setSceneType = iterUnion->second;
				setSceneType.insert(info.unionSceneType);
			}
			else
			{
				SET_INT32 setSceneType;
				setSceneType.clear();
				setSceneType.insert(info.unionSceneType);
				mapUnionScene[unionId] = setSceneType;
			}
		}
		//
		setDelDup.insert(info.sceneId);
	}

	SET_UINT32::iterator iterDelDup = setDelDup.begin();
	for (; iterDelDup != setDelDup.end(); ++iterDelDup)
	{
		uint32_t sceneId = (*iterDelDup);
		dupEnd(sceneId,RET_FAIL);//副本结束
		dupDestory(sceneId); //副本销毁
	}

	g_GetUnionMgr()->OnUnionSceneClose(mapUnionScene);
}

//角色登陆
void CenterDuplicateMgr::onCharacterLogin(ActiveCharacter *pOnlineCharacter)
{
	_UNUSE(pOnlineCharacter);
}
//角色登出
void CenterDuplicateMgr::onCharacterLogout(ActiveCharacter *pOnlineCharacter)
{
	//登出处理，暂时没有
	_UNUSE(pOnlineCharacter);
	CharIDType charId = pOnlineCharacter->GetCharID();
	DupQueue *pQueue = getCharQueue(charId);
	if (nullptr != pQueue)
	{
		pQueue->DelQueue(charId); //暂时这么处理
	}

}
//角色更新
void CenterDuplicateMgr::onCharacterUpdate(ActiveCharacter *pOnlineCharacter)
{
	//暂时没有
	_UNUSE(pOnlineCharacter);
}
//删除角色
void CenterDuplicateMgr::onCharacterDel(OfflineCharacterData *pOffLineCharacter)
{
	_UNUSE(pOffLineCharacter);
	//删除角色处理
	/*MAP_UINT32_UINT32::iterator iter = m_mapCharWaitDup.find(pOffLineCharacter->GetCharID());
	if (iter != m_mapCharWaitDup.end())
	{
		delWaitDuplicate(iter->second);
	}
	MAP_UINT32_UINT32::iterator iterEx = m_mapCharDup.find(pOffLineCharacter->GetCharID());
	if (iterEx != m_mapCharDup.end())
	{
		delDuplicate(iterEx->second);
	}*/
}

void CenterDuplicateMgr::OnTimer(uint32_t nTimerID)
{
	switch (nTimerID)
	{
	case ETimer_ID_Check_Queue:
		{
			checkQueue();
		}
		break;
	}
}

//通知创建副本成功
bool CenterDuplicateMgr::notifyCreateSuccess(uint32_t sceneId)
{
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr == pdupInfo)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::notifyCreateSuccess...nullptr == pdupInfo , sceneid:%u ", sceneId);
		return false;
	}
	bool ret = false;
	CharIDType charId = 0;
	if (EDuplicateKeyType_Union == pdupInfo->keyType)
	{
		//创建工会相关场景成功，通知工会
		if (!g_GetUnionMgr()->CreateUnionSceneRes((uint32_t)pdupInfo->keyValue, pdupInfo->unionSceneType, pdupInfo->sceneId))
		{
			//如果失败，副本设置成结束
			pdupInfo->isEnd = true;
		}
		else
		{
			ret = true;

			//创建副本之后，需要进副本的玩家需要通知进入副本，目前只有云端试炼或者工会活动地宫 才需要进入副本，后面有新加的都需要添加
			if (EUnionSceneType_Cloud == pdupInfo->unionSceneType
				|| EUnionSceneType_DunGeon == pdupInfo->unionSceneType
				)
			{
				//创建副本成功，通知玩家进入副本
				ret = notifyEnterDup(pdupInfo->sceneId, pdupInfo->cid);
				charId = pdupInfo->cid;
			}
		}
	}
	else if (EDuplicateKeyType_Single == pdupInfo->keyType
		|| EDuplicateKeyType_Team == pdupInfo->keyType
		|| EDuplicateKeyType_Room == pdupInfo->keyType
		|| EDuplicateKeyType_Arena == pdupInfo->keyType
		|| EDuplicateKeyType_Pestilence == pdupInfo->keyType
		)
	{
		ret = notifyEnterDup(pdupInfo->sceneId);
		charId = pdupInfo->keyValue;
	}
	else if (EDuplicateKeyType_Compete == pdupInfo->keyType)
	{
		ret = notifyEnterDup(pdupInfo->sceneId);
		charId = pdupInfo->cid;
	}
	if (!ret)
	{
		//失败，直接通知进入失败
		notifyEnterFailed(charId, pdupInfo->dupId, RET_FAIL);
	}

	return ret;
}

//通知进入副本
bool CenterDuplicateMgr::notifyEnterDup(uint32_t sceneId, CharIDType charId /*= 0*/)
{
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr == pdupInfo)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup...nullptr == pdupInfo , sceneid:%u ", sceneId);
		return false;
	}
	bool ret = false;
	if (EDuplicateKeyType_Single == pdupInfo->keyType
		|| EDuplicateKeyType_Arena == pdupInfo->keyType
			
		) //如果是单人的话直接通知进副本（创建副本场景之前已经验证过进副本的条件）
	{
		ret = notifyCharEnterDup(pdupInfo->keyValue, pdupInfo);
	}
	else if (EDuplicateKeyType_Union == pdupInfo->keyType)
	{
		ret = notifyCharEnterDup(charId, pdupInfo); //这里的 charid 外部传进来时，不允许为0 
	}
	else if (EDuplicateKeyType_Team == pdupInfo->keyType)
	{
		bool bflag = false;
		DupTeamState *pTeamState = getDupTeamState((uint32_t)pdupInfo->keyValue);
		if (nullptr != pTeamState)
		{
			if (!pTeamState->isCreate())
			{
				LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup....pTeamState->isCreate() return false ....cid:%lu, dupid:%u, sceneid:%u, keytype:%d, keyvalue:%u ", pdupInfo->cid, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, (uint32_t)pdupInfo->keyValue);
				return false;
			}
			//开始进入副本状态
			pTeamState->startEnter();
			//
			const MAP_UINT64_INT8 *pCharState = pTeamState->getState();
			if (nullptr == pCharState)
			{
				LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup....nullptr == pCharState...cid:%lu, dupid:%u, sceneid:%u, keytype:%d, keyvalue:%u ", pdupInfo->cid, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, (uint32_t)pdupInfo->keyValue);
				return false;
			}
			auto iter = pCharState->begin();
			for (; iter != pCharState->end(); ++iter)
			{
				CharIDType charId = iter->first;

				if (notifyCharEnterDup(charId,pdupInfo))
				{
					bflag = true;
				}
			}
			if (bflag)
			{
				ret = true;
			}
			else
			{
				//失败，回收状态
				RecycleTeamState(pTeamState);
			}
		}
	}
	else if (EDuplicateKeyType_Room == pdupInfo->keyType)
	{
		//直接通知房员进入副本
		Room *room = g_GetRoomMgr()->getRoom((uint32_t)pdupInfo->keyValue);
		if (nullptr != room)
		{
			if (room->state() == ERoomState_Create)
			{
				//创建副本完成之后，房间开始倒计时
				if (nullptr == g_GetRoomMgr()->startCountDown((uint32_t)pdupInfo->keyValue))
				{
					LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup....create state ....g_GetRoomMgr()->startCountDown return nullptr , cid:%lu,  dupid:%u, sceneid:%u, keytype:%d, keyvalue:%u ", pdupInfo->cid, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, (uint32_t)pdupInfo->keyValue);
					return false;
				}
				return true;
			}
			if (room->state() != ERoomState_Enter) //倒计时结束后会进入进入副本状态
			{
				LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup....room->state() != ERoomState_Enter , cid:%lu,  dupid:%u, sceneid:%u, keytype:%d, keyvalue:%u,state:%d ", pdupInfo->cid, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, (uint32_t)pdupInfo->keyValue, room->state());
				return false;
			}

			bool flag = false;
			RoomMemberMap &memberMap = room->allMember();
			RoomMemberMap::iterator iter = memberMap.begin();
			for (; iter != memberMap.end(); ++iter)
			{
				CharIDType charId = iter->first;
				if (notifyCharEnterDup(charId,pdupInfo))
				{
					flag = true;
				}
			}
			if (flag)
			{
				ret = true;
			}
			else
			{
				//失败，重置状态
				g_GetRoomMgr()->resetState((uint32_t)pdupInfo->keyValue);
			}
		}
		else
		{
			LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup....room can not find ....roomid:%u , dupid:%u ,sceneid:%u ", (uint32_t)pdupInfo->keyValue, pdupInfo->dupId, pdupInfo->sceneId);
		}
	}
	else if (EDuplicateKeyType_Pestilence == pdupInfo->keyType)
	{
		bool flag = false;
		DupQueue *pQueue = getQueue((int32_t)pdupInfo->keyValue);
		if (nullptr != pQueue)
		{
			if (pQueue->IsFull())
			{
				if (pQueue->IsReady())
				{
					SET_UINT64 setChar;
					setChar.clear();
					pQueue->QueueAllChar(setChar);
					SET_UINT64::iterator iterChar = setChar.begin();
					for (; iterChar != setChar.end(); ++iterChar)
					{
						CharIDType charId = (*iterChar);
						if (notifyCharEnterDup(charId, pdupInfo))
						{
							flag = true;
						}
					}
					if (flag)
					{
						ret = true;
					}
					else
					{
						//失败，清空准备状态
						pQueue->ClearReady();
					}
				}
				else
				{
					LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup....queue not ready state ....queueid:%u , dupid:%u ,sceneid:%u ", (uint32_t)pdupInfo->keyValue, pdupInfo->dupId, pdupInfo->sceneId);
				}
			}
			else
			{
				LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup....queue not full ....queueid:%u , dupid:%u ,sceneid:%u ", (uint32_t)pdupInfo->keyValue, pdupInfo->dupId, pdupInfo->sceneId);
			}
		}
		else
		{
			LogErrFmtPrint("[center] CenterDuplicateMgr::notifyEnterDup...can not find queue ....queueid:%u , dupid:%u ,sceneid:%u ", (uint32_t)pdupInfo->keyValue, pdupInfo->dupId, pdupInfo->sceneId);
		}
	}
	else if (EDuplicateKeyType_Compete == pdupInfo->keyType)
	{
		if (pdupInfo->mapCharBorn.size() < 2)
			return ret;
		MAP_UINT64_UINT32::iterator iter = pdupInfo->mapCharBorn.begin();
		if (notifyCharEnterDup(iter->first, pdupInfo))
		{
			++iter;
			return notifyCharEnterDup(iter->first, pdupInfo);
		}
	}

	return ret;
}

//通知单个玩家进入副本
bool CenterDuplicateMgr::notifyCharEnterDup(CharIDType charId, dupInfo *pdupInfo)
{
	if (nullptr == pdupInfo)
	{
		return false;
	}
	uint32_t logicId = g_GetCenterAccountMgr()->GetLogicIdByCid(charId);
	CenterToLogic_DuplicateEnterNotify notify;
	notify.set_char_id(charId);
	notify.set_duplicate_id(pdupInfo->dupId);
	notify.set_scene_id(pdupInfo->sceneId);
	
	if (EDuplicateKeyType_Pestilence == pdupInfo->keyType || EDuplicateKeyType_Compete == pdupInfo->keyType)
	{
		MAP_UINT64_UINT32::iterator iterBorn = pdupInfo->mapCharBorn.find(charId);
		if (iterBorn != pdupInfo->mapCharBorn.end())
		{
			notify.set_born_id(iterBorn->second);
		}		
	}
	if (!g_GetCenterService()->SendDataToLogic(logicId, EMODULE_ID_DUPLICATE, CENTER_TO_LOGIC_DUPLICATE_NOTIFY_ENTER, &notify))
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::notifyCharEnterDup....SendDataToLogic failed, cid:%llu, logicid:%u,  dupid:%u, sceneid:%u, keytype:%d, keyvalue:%llu ", charId, logicId, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, pdupInfo->keyValue);
	}
	else
	{
		waitEnter(charId, pdupInfo->sceneId);
		return true;
	}
	return false;
}

//获取排队人数上限
bool CenterDuplicateMgr::getQueueMaxNum(int32_t &maxNum, int32_t &injectInitNum, int32_t &surviveInitNum)
{
	LuaScript *pScript = g_GetCSScriptMgr()->GetScript();
	if (nullptr == pScript)
	{
		LogErrFmtPrint("[logic] CenterDuplicateMgr::getQueueMaxNum....nullptr == pScript... ");
		return false;
	}
	LuaRef ref(pScript->GetState());
	if (!pScript->CallTableFuncRet("Activity", "LuaPestilenceWarCount", ref))
	{
		LogErrFmtPrint("CenterDuplicateMgr::getQueueMaxNum...pScript->CallTableFuncRet failed....");
		return false;
	}
	if (!ref.isTable())
	{
		LogErrFmtPrint("CenterDuplicateMgr::getQueueMaxNum...ref.isTable() return false....");
		return false;
	}
	if (ref.length() != 3)
	{
		LogErrFmtPrint("CenterDuplicateMgr::getQueueMaxNum...ref.length() != 3....");
		return false;
	}
	maxNum = ref[1].cast<int32_t>();
	injectInitNum = ref[2].cast<int32_t>();
	surviveInitNum = ref[3].cast<int32_t>();

	return true;
}
//分配玩家出生点
bool CenterDuplicateMgr::allocCharBorn(SET_UINT64 &setChar, uint32_t dupId, int32_t injectNum, int32_t surviveNum, MAP_UINT64_UINT32 &mapCharBorn)
{
	const DuplicateDuplicateCfgInfo *pDupCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
	if (nullptr == pDupCfg)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::allocCharBorn....nullptr == pDupCfg, dupid:%u ", dupId);
		return false;
	}
	uint32_t mapId = pDupCfg->sceneResource;
	const SET_UINT32 *pInjectSet = g_GetTeleportCfgMgr()->GetMapTeleportBornByCamp(mapId, ETeleportCamp_Inject);
	const SET_UINT32 *pSurviveSet = g_GetTeleportCfgMgr()->GetMapTeleportBornByCamp(mapId, ETeleportCamp_Survive);
	if (nullptr == pInjectSet || nullptr == pSurviveSet)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::allocCharBorn....nullptr == pInjectSet || nullptr == pSurviveSet,,mapd:%u ", mapId);
		return false;
	}
	if ((int32_t)pInjectSet->size() < injectNum || (int32_t)pSurviveSet->size() < surviveNum)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::allocCharBorn....pInjectSet->size() < injectNum || (int32_t)pSurviveSet->size() < surviveNum,,mapd:%u ,injectNum:%d , surviveNum:%d ", mapId, injectNum,surviveNum);
		return false;
	}
	if ((int32_t)setChar.size() > (injectNum + surviveNum))
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::allocCharBorn....(int32_t)setChar.size() > (injectNum + surviveNum),,mapd:%u ,injectNum:%d , surviveNum:%d , charNum:%d ", mapId, injectNum, surviveNum,(int32_t)setChar.size());
		return false;
	}
	//给玩家分配出生点
	SET_UINT32::const_iterator iterInject = pInjectSet->begin();
	SET_UINT32::const_iterator iterInjectEnd = pInjectSet->end();
	SET_UINT32::const_iterator iterSurvive = pSurviveSet->begin();
	SET_UINT32::const_iterator iterSurviveEnd = pSurviveSet->end();
	int32_t injectCur = 0;
	int32_t survivieCur = 0;
	SET_UINT64::iterator iterChar = setChar.begin();
	for (; iterChar != setChar.end(); ++iterChar)
	{
		CharIDType charId = (*iterChar);
		//先分配感染者
		if (injectCur < injectNum)
		{
			if (iterInject != iterInjectEnd)
			{
				mapCharBorn[charId] = (*iterInject);
				//
				++injectCur;
				++iterInject;
			}

		}
		else
		{
			//分配生还者
			if (iterSurvive != iterSurviveEnd)
			{
				mapCharBorn[charId] = (*iterSurvive);
				//
				++survivieCur;
				++iterSurvive;
			}
		}

	}

	return true;
}
//获取队列
DupQueue *CenterDuplicateMgr::getQueue(int32_t queueId)
{
	DupQueueMap::iterator iter = m_mapQueue.find(queueId);
	return (iter != m_mapQueue.end()) ? iter->second : nullptr;
}
//获取玩家所在的排队
DupQueue *CenterDuplicateMgr::getCharQueue(CharIDType charId)
{
	DupQueueMap::iterator iter = m_mapQueue.begin();
	for (; iter != m_mapQueue.end(); ++iter)
	{
		DupQueue *pQueue = iter->second;
		if (nullptr != pQueue  && pQueue->InQueue(charId))
		{
			return pQueue;
		}
	}
	return nullptr;
}
//是否在排队
bool CenterDuplicateMgr::inQueue(CharIDType charId)
{
	return (nullptr != getCharQueue(charId));
}

//队伍是否在排队
bool CenterDuplicateMgr::teamQueue(uint32_t teamId)
{
	DupQueueMap::iterator iter = m_mapQueue.begin();
	for (; iter != m_mapQueue.end(); ++iter)
	{
		DupQueue *pQueue = iter->second;
		if (nullptr != pQueue  && pQueue->HasTeamQueue(teamId))
		{
			return true;
		}
	}
	return false;
}

//能否容纳
DupQueue *CenterDuplicateMgr::canAddQueue(SET_UINT64 &setChar, uint32_t teamId/* = 0*/)
{
	int32_t num = (int32_t)setChar.size();
	DupQueueMap::iterator iter = m_mapQueue.begin();
	for (; iter != m_mapQueue.end(); ++iter)
	{
		DupQueue *pQueue = iter->second;
		if (nullptr != pQueue && !pQueue->IsFull())
		{
			if (num <= pQueue->RemainNum())
			{
				pQueue->AddQueue(setChar, teamId);
				return pQueue;
			}
		}
	}
	return nullptr;
}
//能否匹配
DupQueue *CenterDuplicateMgr::canMatchQueue(SET_UINT64 &setChar, uint32_t teamId /*= 0*/)
{
	int32_t num = (int32_t)setChar.size();
	DupQueueMap::iterator iter = m_mapQueue.begin();
	for (; iter != m_mapQueue.end(); ++iter)
	{
		DupQueue *pQueue = iter->second;
		if (nullptr != pQueue && !pQueue->IsFull())
		{
			if (num == pQueue->RemainNum())
			{
				pQueue->AddQueue(setChar, teamId);
				return pQueue;
			}
		}
	}
	return nullptr;
}
//能否替换
DupQueue *CenterDuplicateMgr::canReplace(uint32_t teamId,SET_UINT64 &setChar, uint32_t &replaceTeamId, SET_UINT64 &setMember)
{
	DupQueueMap::iterator iter = m_mapQueue.begin();
	for (; iter != m_mapQueue.end(); ++iter)
	{
		DupQueue *pQueue = iter->second;
		if (nullptr != pQueue)
		{
			if (pQueue->CanFullByReplace(setChar, replaceTeamId, setMember))
			{
				//可以替换,删除旧的组队，增加新的组队  
				pQueue->DelTeamQueue(replaceTeamId);
				pQueue->AddQueue(setChar, teamId);
				return pQueue;
			}
		}
	}
	return nullptr;
}

//加入排队
DupQueue * CenterDuplicateMgr::onJoinQueue(SET_UINT64 &setChar, uint32_t teamId /*= 0*/, bool notify /*= true*/)
{
	int32_t num = setChar.size();
	if (num <= 0)
	{
		return nullptr;
	}
	//先检查是否有队列匹配
	DupQueue *pMatchQueue = canMatchQueue(setChar, teamId);
	if (nullptr != pMatchQueue)
	{
		return pMatchQueue;
	}
	//先检查是否有队列刚好容纳
	DupQueue *pAddQueue = canAddQueue(setChar, teamId);
	if (nullptr != pAddQueue)
	{
		return pAddQueue;
	}
	bool result = false;
	DupQueue *pResultQueue = nullptr;
	bool new_queue = true;
	SET_UINT64 setFinal = setChar;
	uint32_t finalTeamId = teamId;
	if (teamId > 0) //组队的，检查是否可以替换某一个队列中其他组队的人员，使这个队列满足 进入副本的条件
	{
		uint32_t replaceTeamId = 0;
		SET_UINT64 setMember;
		setMember.clear();
		DupQueue *pReplaceQueue = canReplace(teamId, setChar, replaceTeamId, setMember);
		if (nullptr != pReplaceQueue)
		{
			//替换成功，说明 替换进队列的队伍人数 和 替换出队列的队伍人数 不同 
			//替换出来的队伍 再在剩下的队列中 匹配和替换 可能会有其他的队列能匹配的上 或者替换其他队列中组队
			result = true;
			pResultQueue = pReplaceQueue;
			setFinal = setMember;
			finalTeamId = replaceTeamId;			
			bool bend = false;
			while (!bend)
			{
				DupQueue *pMatchQueueEx = canMatchQueue(setMember, replaceTeamId);
				if (nullptr == pMatchQueueEx)
				{
					//没有匹配的，检查是否有替换
					uint32_t replaceTeamIdEx = replaceTeamId;
					SET_UINT64 setMemberEx = setMember;
					replaceTeamId = 0;
					setMember.clear();
					DupQueue *pReplaceQueueEx = canReplace(replaceTeamIdEx, setMemberEx, replaceTeamId, setMember);
					if (nullptr != pReplaceQueueEx)
					{
						//替换成功，新建一个队列
						setFinal = setMember;
						finalTeamId = replaceTeamId;
					}
					else
					{
						//没有匹配的，也没有可替换的
						bend = true;			//结束
					}
				}
				else
				{
					//有匹配的,已经匹配到队列了，后面不需要在新建队列
					bend = true;			//结束
					new_queue = false;		//不需要新建队列					
					setFinal.clear();
					finalTeamId = 0;
				}
			}		
			
		}
	}
	if (new_queue && setFinal.size() > 0) //需要新建队列，并且加入人数大于0
	{
		//新建队列
		DupQueue *pNewQueue = CreateQueue();
		if (nullptr != pNewQueue)
		{
			pNewQueue->AddQueue(setFinal, finalTeamId);
			if (!result)
			{
				result = true;
				pResultQueue = pNewQueue;
			}
		}
		else
		{
			//这里处理失败的情况
			string strerr = "";
			SET_UINT64::iterator iterFinal = setFinal.begin();
			for (; iterFinal != setFinal.end(); ++iterFinal)
			{
				CharIDType finalCharId = (*iterFinal);
				char szTmp[20] = { '\0' };
				snprintf(szTmp,20, "%lu,", finalCharId);
				strerr += szTmp;
			}
			//
			LogErrFmtPrint("[center] CenterDuplicateMgr::onJoinQueue.....nullptr == pNewQueue...teamid:%u, finalTeamid:%u , member:%s ",teamId,finalTeamId,strerr.c_str());
		}
	}
	if (nullptr != pResultQueue && notify)
	{
		//通知排队
		notifyJoinQueue(setChar);
	}

	return pResultQueue;
}


//检查排队，是否能匹配进入副本
void CenterDuplicateMgr::checkQueue()
{
	DupQueueMap::iterator iter = m_mapQueue.begin();
	for (; iter != m_mapQueue.end(); ++iter)
	{
		DupQueue *pQueue = iter->second;
		if (nullptr != pQueue && pQueue->IsFull() && !pQueue->IsReady())
		{
			//队列满了，还没有准备的，直接进副本
			LogicToCenter_EnterDupReq enterReq;
			enterReq.set_charid(0);
			enterReq.set_duplicate_id(g_GetDuplicateCfgMgr()->GetPestilenceDupId());
			enterReq.set_key_type(EDuplicateKeyType_Pestilence);
			enterReq.set_key_value(pQueue->QueueId());
			SET_UINT64 setChar;
			setChar.clear();
			MAP_UINT64_UINT32 mapCharBorn;
			mapCharBorn.clear();
			pQueue->QueueAllChar(setChar);
			if (allocCharBorn(setChar, enterReq.duplicate_id(), pQueue->InjectInitNum(), pQueue->SurviveInitNum(), mapCharBorn))
			{
				MAP_UINT64_UINT32::iterator iterBorn = mapCharBorn.begin();
				for (; iterBorn != mapCharBorn.end(); ++iterBorn)
				{
					DupBornProto *protoBorn = enterReq.add_char_born();
					if (nullptr != protoBorn)
					{
						protoBorn->set_charid(iterBorn->first);
						protoBorn->set_bornid(iterBorn->second);
					}
				}
				uint32_t dupSceneId = 0;
				if (RET_SUCCESS != enterDupReq(enterReq, dupSceneId))
				{
					LogErrFmtPrint("[center] CenterDuplicateMgr::checkQueue....enterDupReq failed...queueid:%d  ", pQueue->QueueId());
				}
			}
			
		}
	}
}

//通知进入排队
void CenterDuplicateMgr::notifyJoinQueue(SET_UINT64 &setChar)
{
	SET_UINT64::iterator iter = setChar.begin();
	for (; iter != setChar.end(); ++iter)
	{
		CharIDType charId = (*iter);
		Duplicate_NotifyJoinQueueRsp notify;
		g_GetCenterService()->SendDataToClient(charId, EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_NOTIFY_JOIN_QUEUE, &notify);
	}	
}


dupInfo *CenterDuplicateMgr::createDuplicate(dupInfo &info)
{
	if (getDuplicate(info.sceneId))
	{
		return nullptr;
	}
	m_mapDupData[info.sceneId] = info;

	return &m_mapDupData[info.sceneId];
}

//获取副本
dupInfo *CenterDuplicateMgr::getDuplicate(uint32_t sceneId)
{
	DupDataMap::iterator iter = m_mapDupData.find(sceneId);
	return (iter != m_mapDupData.end()) ? &iter->second : nullptr;
}
//等待玩家进入副本
bool CenterDuplicateMgr::waitEnter(CharIDType charId, uint32_t sceneId)
{
	dupInfo *pdup = getDuplicate(sceneId);
	if (nullptr == pdup)
	{
		return false;
	}
	addDupWaitRet(charId, sceneId);
	return true;
}
//玩家进入副本
bool CenterDuplicateMgr::enterDup(CharIDType charId, uint32_t sceneId, int32_t result)
{
	dupInfo *pdup = getDuplicate(sceneId);
	if (nullptr == pdup)
	{
		return false;
	}
	//删除等待进入副本
	delDupWaitRet(charId);
	//
	if (RET_SUCCESS == result)
	{
		//进入副本
		pdup->setEnter.insert(charId);
		//添加副本玩家
		addDupChar(charId, sceneId);
		//房间处理
		if (EDuplicateKeyType_Room == pdup->keyType)
		{
			//房间玩家进入副本，修改房间状态
			if (nullptr == g_GetRoomMgr()->enterSuccess((uint32_t)pdup->keyValue))
			{
				LogErrFmtPrint("[center] CenterDuplicateMgr::enterDup ....g_GetRoomMgr()->enterSuccess failed.....dupid:%u, sceneid:%u, keytype:%d, keyval:%u ", pdup->dupId, pdup->sceneId, pdup->keyType, (uint32_t)pdup->keyValue);
			}
		}
		else if (EDuplicateKeyType_Team == pdup->keyType)
		{
			DupTeamState *pTeamState = getDupTeamState((uint32_t)pdup->keyValue);
			if (nullptr != pTeamState)
			{
				pTeamState->enterSuccess();
			}
		}
	}

	return true;
}
//玩家离开副本
bool CenterDuplicateMgr::leaveDup(CharIDType charId, uint32_t sceneId)
{
	dupInfo *pdup = getDuplicate(sceneId);
	if (nullptr == pdup)
	{
		return false;
	}
	pdup->setEnter.erase(charId);

	//删除副本内玩家
	delDupChar(charId);

	/*if (EDuplicateKeyType_Room == pdup->keyType)
	{
		//g_GetRoomMgr()->leaveDup(charId);
	}
	else if (EDuplicateKeyType_Team == pdup->keyType)
	{
		DupTeamState *pTeamState = getDupTeamState((uint32_t)pdup->keyValue);
		if (nullptr != pTeamState)
		{
			//处理
		}
	}*/

	return true;
}
//副本开始
bool CenterDuplicateMgr::dupBegin(uint32_t sceneId)
{
	dupInfo *pdup = getDuplicate(sceneId);
	if (nullptr == pdup)
	{
		return false;
	}
	pdup->isBegin = true;
	pdup->setEnter.clear();

	return true;
}
//副本结束
bool CenterDuplicateMgr::dupEnd(uint32_t sceneId, int32_t res)
{
	dupInfo *pdup = getDuplicate(sceneId);
	if (nullptr == pdup)
	{
		return false;
	}
	pdup->isEnd = true;
	pdup->res = res;

	//日志
	char szParm[200] = { '\0' };
	snprintf(szParm, 199, " CenterDuplicateMgr::dupEnd...dupid:%u, sceneid:%u,keyType:%u,keyValue:%lu,unionSceneType:%d ....charlist:",pdup->dupId,pdup->sceneId,pdup->keyType,pdup->keyValue,pdup->unionSceneType);
	string strLog = szParm;
	//结束的时候
	auto iterChar = pdup->setEnter.begin();
	for (; iterChar != pdup->setEnter.end(); ++iterChar)
	{
		CharIDType charId = (*iterChar);
		delDupChar(charId);
		delDupWaitRet(charId);
		delWaitCreate(charId);

		char szTemp[20] = { '\0' };
		snprintf(szTemp, 19, ",%lu", charId);
		strLog += szTemp;
	}
	LogDebugFmtPrint("[center] %s ", strLog.c_str());

	if (EDuplicateKeyType_Room == pdup->keyType)
	{
		//副本结束，解散房间,副本结束不用通知副本处理离开房间
		g_GetRoomMgr()->dismissRoom((uint32_t)pdup->keyValue,0);
	}
	else if (EDuplicateKeyType_Team == pdup->keyType)
	{
		DupTeamState *pTeamState = getDupTeamState((uint32_t)pdup->keyValue);
		if (nullptr != pTeamState)
		{
			RecycleTeamState(pTeamState);
		}
	}
	else if (EDuplicateKeyType_Pestilence == pdup->keyType)
	{
		DupQueue *pQueue = getQueue((int32_t)pdup->keyValue);
		if (nullptr != pQueue)
		{
			RecycleQueue(pQueue);
		}
	}


	return true;
}
//副本销毁
bool CenterDuplicateMgr::dupDestory(uint32_t sceneId)
{
	DupDataMap::iterator iter = m_mapDupData.find(sceneId);
	if (iter != m_mapDupData.end())
	{
		m_mapDupData.erase(iter);
		return true;
	}
	return false;
}

//工会解散
bool CenterDuplicateMgr::unionDismiss(uint32_t sceneId)
{
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr != pdupInfo)
	{
		pdupInfo->isEnd = true;
	}
	return true;
}

//工会云端试炼活动结束
bool CenterDuplicateMgr::unionActEnd(uint32_t sceneId)
{
	dupInfo *pDupInfo = getDuplicate(sceneId);
	if (nullptr != pDupInfo)
	{
		pDupInfo->isEnd = true;
	}

	return true;
}

//登录是否能进入
bool CenterDuplicateMgr::loginCanEnter(uint32_t sceneId,CharIDType charId)
{
	bool canEnter = true;
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr != pdupInfo)
	{
		if (pdupInfo->isEnd) //副本已经结束不能进入
		{
			canEnter = false;
		}
		else if (EDuplicateKeyType_Single == pdupInfo->keyType
			|| EDuplicateKeyType_Arena == pdupInfo->keyType
			|| EDuplicateKeyType_Pestilence == pdupInfo->keyType
			)
		{
			//单人、竞技场、瘟疫之战多人PVP  副本 登录需要重置
			canEnter = false;
		}
		else if (EDuplicateKeyType_Union == pdupInfo->keyType)
		{
			if (EUnionSceneType_Home == pdupInfo->unionSceneType || EUnionSceneType_DunGeon == pdupInfo->unionSceneType)
			{
				//公会驻地和工会活动地宫 场景
				if (g_GetUnionMgr()->GetCharUnionId(charId) != (uint32_t)pdupInfo->keyValue)
				{
					canEnter = false;
				}
			}
			else if (EUnionSceneType_Cloud == pdupInfo->unionSceneType)
			{
				//工会云端试炼，登录需要重置
				canEnter = false;
			}
		}
		else if (EDuplicateKeyType_Team == pdupInfo->keyType)
		{
			//组队 多人PVE副本， 登录校验,
			if (g_GetTeamMgr()->GetTeamId(charId) != (uint32_t)pdupInfo->keyValue)
			{
				canEnter = false;
			}
		}
		else if(EDuplicateKeyType_Room == pdupInfo->keyType)
		{
			//房间 多人PVE副本， 登录校验
			if (g_GetRoomMgr()->getCharRoom(charId) != (uint32_t)pdupInfo->keyValue)
			{
				canEnter = false;
			}
		}
	}
	return canEnter;
}

//生物切场景是否能进入
bool CenterDuplicateMgr::transCanEnter(uint32_t sceneId, uint64_t creature_cid, int32_t creature_kind)
{
	bool canEnter = true;
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr != pdupInfo)
	{
		if (pdupInfo->isEnd) //副本已经结束不能进入
		{
			canEnter = false;
		}
		else if (EUnionSceneType_Home == pdupInfo->unionSceneType
			|| EUnionSceneType_DunGeon == pdupInfo->unionSceneType
			)
		{
			//公会驻地和 工会活动地宫 场景，生物是人的话需要判断玩家的工会，其他生物暂时不做判断
			if (CREATURE_PLAYER == creature_kind)
			{
				if (g_GetUnionMgr()->GetCharUnionId(creature_cid) != (uint32_t)pdupInfo->keyValue)
				{
					canEnter = false;
				}
			}
		}
	}
	return canEnter;
}

//获取副本场景所在的逻辑服ID
uint32_t CenterDuplicateMgr::dupSceneLogic(uint32_t sceneId)
{
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr != pdupInfo)
	{
		return pdupInfo->logicServerId;
	}
	return 0;
}

//能否加入排队
int32_t CenterDuplicateMgr::canJoinQueue(CharIDType charId)
{
	int32_t ret = RET_SUCCESS;
	uint32_t actId = g_GetDuplicateCfgMgr()->GetPestilenceActId();
	ActiveCharacter *pOnline = g_GetActiveCharacterMgr()->GetOnlineCharacter(charId);
	if (nullptr == pOnline)
	{
		//不在线
		ret = RET_NOT_ONLINE;
	}
	else if (!g_GetActivityMgr()->IsActivityRunning(actId))
	{
		//活动未开启
		ret = RET_ACTIVITY_NOT_OPEN;
	}
	else
	{
		uint32_t teamId = g_GetTeamMgr()->GetTeamId(charId);
		if (teamId > 0)
		{
			if (nullptr != getDupTeamState(teamId))
			{
				ret = RET_DUPLICATE_CAN_NOT_QUEUE;
			}
			else if (teamQueue(teamId))
			{
				//已经在排队中
				ret = RET_DUPLICATE_ALREADY_IN_QUEUE;
			}
		}
		else if (inQueue(charId))
		{
			//已经在排队中
			ret = RET_DUPLICATE_ALREADY_IN_QUEUE;
		}
	}	

	return ret;
}
//加入排队
DupQueue * CenterDuplicateMgr::joinQueue(CharIDType charId)
{
	SET_UINT64 setChar;
	setChar.clear();
	uint32_t teamId = g_GetTeamMgr()->GetTeamId(charId);
	if (teamId > 0)
	{
		Team *pTeam = g_GetTeamMgr()->FindTeam(teamId);
		if (nullptr == pTeam)
		{
			return nullptr;
		}
		pTeam->GetMemeberList(setChar);
	}
	else
	{
		setChar.insert(charId);
	}
	if (setChar.size() <= 0)
	{
		return nullptr;
	}
	return onJoinQueue(setChar, teamId);
}

//能否取消排队
int32_t CenterDuplicateMgr::canCancelQueue(CharIDType charId)
{
	//这里需要判断活动时间
	int32_t ret = RET_SUCCESS;
	ActiveCharacter *pOnline = g_GetActiveCharacterMgr()->GetOnlineCharacter(charId);
	if (nullptr == pOnline)
	{
		//不在线
		ret = RET_NOT_ONLINE;
	}
	DupQueue *pQueue = getCharQueue(charId);
	if (nullptr == pQueue)
	{
		//不在排队状态
		ret = RET_DUPLICATE_NOT_IN_QUEUE;
	}
	else if (pQueue->IsReady())
	{
		ret = RET_DUPLICATE_CAN_NOT_CANCEL_QUEUE;
	}
	return ret;
}
//取消排队
bool CenterDuplicateMgr::cancelQueue(CharIDType charId)
{
	DupQueue *pQueue = getCharQueue(charId);
	if (nullptr != pQueue)
	{
		pQueue->DelQueue(charId);

		return true;
	}
	return false;
}



//获取等待玩家数据
dupWaitRet *CenterDuplicateMgr::getDupWaitRet(CharIDType charId)
{
	DupWaitRetMap::iterator iter = m_mapWaitRet.find(charId);
	return (iter != m_mapWaitRet.end()) ? &iter->second : nullptr;
}
//增加等待玩家数据
void CenterDuplicateMgr::addDupWaitRet(CharIDType charId, uint32_t sceneId)
{
	dupWaitRet waitRet;
	waitRet.sceneId = sceneId;
	waitRet.waitTime = g_GetGlobalServerTime()->UnixSec();
	m_mapWaitRet[charId] = waitRet;
}
//删除等待玩家数据
void CenterDuplicateMgr::delDupWaitRet(CharIDType charId)
{
	m_mapWaitRet.erase(charId);
}

//获取副本玩家数据
uint32_t CenterDuplicateMgr::getDupChar(CharIDType charId)
{
	auto iter = m_mapDupChar.find(charId);
	return (iter != m_mapDupChar.end()) ? iter->second : 0;
}
//增加副本玩家数据
void CenterDuplicateMgr::addDupChar(CharIDType charId, uint32_t sceneId)
{
	m_mapDupChar[charId] = sceneId;
}
//删除副本玩家数据
void CenterDuplicateMgr::delDupChar(CharIDType charId)
{
	m_mapDupChar.erase(charId);
}

//获取等待创建工会云端试炼副本
uint32_t CenterDuplicateMgr::getWaitCreateUnion(uint32_t unionId)
{
	MAP_UINT32_UINT32::iterator iter = m_mapWaitCreateUnion.find(unionId);
	return (iter != m_mapWaitCreateUnion.end()) ? iter->second : 0;
}
//添加等待创建工会云端试炼副本
void CenterDuplicateMgr::addWaitCreateUnion(uint32_t unionId, uint32_t sceneId)
{
	m_mapWaitCreateUnion[unionId] = sceneId;
}
//删除等待创建工会云端试炼副本
void CenterDuplicateMgr::delWaitCreateUnion(uint32_t unionId)
{
	m_mapWaitCreateUnion.erase(unionId);
}


//获取副本队伍状态
DupTeamState *CenterDuplicateMgr::getDupTeamState(uint32_t teamId)
{
	DupTeamStateMap::iterator iter = m_teamState.find(teamId);
	return (iter != m_teamState.end()) ? iter->second : nullptr;
}
//是否能邀请进副本
int32_t CenterDuplicateMgr::canInviteEnter(CharIDType charId, uint32_t dupId, Team * &pOutTeam)
{
	const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
	if (nullptr == pcfg)
	{
		return RET_FAIL;
	}
	//根据charId 取队伍
	Team *pTeam = g_GetTeamMgr()->FindTeam(charId);
	if (nullptr == pTeam)
	{
		return RET_TEAM_NO_EXIST;
	}
	DupTeamState *pdupState = getDupTeamState(pTeam->TeamID());
	if (nullptr != pdupState)
	{
		return RET_DUPLICATE_TEAM_NOT_INVITE;
	}
	if (!pTeam->IsLeader(charId))
	{
		return RET_DUPLICATE_NOT_TEM_LEADER;
	}

	//判断队伍人数pcfg->playerAmountLowerLimit,pcfg->playerAmountTopLimit
	/*int32_t count = pTeam->MemberCount();
	if (count < pcfg->playerAmountLowerLimit || count > pcfg->playerAmountTopLimit)
	{
		return RET_DUPLICATE_PLAYER_NUM_LIMIT;
	}*/
	//队伍队员目前的状态判断，是否在副本，是否在房间等
	SET_UINT64 setMember;
	setMember.clear();
	pTeam->GetMemeberList(setMember);
	auto iterMem = setMember.begin();
	for (; iterMem != setMember.end(); ++iterMem)
	{
		CharIDType memCharId = (*iterMem);
		ActiveCharacter *pOnline = g_GetActiveCharacterMgr()->GetOnlineCharacter(memCharId);
		if (nullptr == pOnline)
		{
			return RET_DUPLICATE_TEAM_MEM_NOT_ONLINE;
		}
		if (isCharInDup(charId)) 
		{
			return RET_DUPLICATE_TEAM_MEM_ALREADY_IN;
		}
		if (g_GetRoomMgr()->getCharRoom(charId) > 0)
		{
			return RET_DUPLICATE_TEAM_MEM_ALREADY_ROOM;
		}
	}

	//如果是瘟疫之战活动副本
	if (dupId == g_GetDuplicateCfgMgr()->GetPestilenceDupId())
	{
		int32_t ret = canJoinQueue(charId);
		if (RET_SUCCESS != ret)
		{
			return ret;
		}
	}

	pOutTeam = pTeam;

	return RET_SUCCESS;
}

//邀请进副本
DupTeamState *CenterDuplicateMgr::inviteEnter(CharIDType charId, uint32_t dupId)
{
	//根据charId 取队伍
	Team *pTeam = g_GetTeamMgr()->FindTeam(charId);
	if (nullptr != pTeam)
	{
		DupTeamState *pDupTeamState = MakeTeamStateObj();
		if (nullptr == pDupTeamState)
		{
			LogErrFmtPrint("[center] CenterDuplicateMgr::inviteEnter....ptr == pDupTeamState...");
			return nullptr;
		}
		if (!pDupTeamState->init(pTeam,dupId))
		{
			FreeTeamStateObj(pDupTeamState);
			LogErrFmtPrint("[center] CenterDuplicateMgr::inviteEnter....pDupTeamState->init(pTeam,dupId) false...charID:%lu, dupId:%u ", charId,dupId);
			return nullptr;
		}
		m_teamState[pDupTeamState->teamId()] = pDupTeamState;
		//队长默认同意
		pDupTeamState->agree(charId);

		return pDupTeamState;
	}
	return nullptr;
}

//能否回复邀请
int32_t CenterDuplicateMgr::canReplyInvite(CharIDType charId, uint32_t dupId)
{
	//根据charId 取队伍
	Team *pTeam = g_GetTeamMgr()->FindTeam(charId);
	if (nullptr != pTeam)
	{
		DupTeamState *pdupState = getDupTeamState(pTeam->TeamID());
		if (nullptr == pdupState)
		{
			return RET_DUPLICATE_TEAM_NOT_REPLY;
		}
		if (EDupTeamCharState_None != pdupState->getState(charId))
		{
			return RET_DUPLICATE_TEAM_ALREADY_REPLY;
		}
		if (pdupState->dupId() != dupId)
		{
			return RET_DUPLICATE_TEAM_NOT_REPLY;
		}
		if (!pdupState->isCountDown())
		{
			return RET_DUPLICATE_TEAM_NOT_REPLY;
		}
		if (dupId == g_GetDuplicateCfgMgr()->GetPestilenceDupId())
		{
			int32_t actId = g_GetDuplicateCfgMgr()->GetPestilenceActId();
			if (!g_GetActivityMgr()->IsActivityRunning(actId))
			{
				return RET_ACTIVITY_NOT_OPEN;
			}
		}

		return RET_SUCCESS;
	}
	else
	{
		return RET_DUPLICATE_NOT_IN_TEAM;
	}
}

//回复邀请
DupTeamState *CenterDuplicateMgr::replyInvite(CharIDType charId, int8_t reply)
{
	//根据charId 取队伍
	Team *pTeam = g_GetTeamMgr()->FindTeam(charId);;
	if (nullptr != pTeam)
	{
		DupTeamState *pdupState = getDupTeamState(pTeam->TeamID());
		if (nullptr == pdupState)
		{
			LogErrFmtPrint("[center] CenterDuplicateMgr::replyInvite...nullptr == pdupState...charid:%lu ,teamid:%u,", charId,pTeam->TeamID());
			return nullptr;
		}
		if (EDupTeamCharState_Agree == reply)
		{
			pdupState->agree(charId);
		}
		else
		{
			pdupState->refuse(charId);
		}
		return pdupState;
	}

	return nullptr;
}

//获取玩家进入之前所在的区域
uint32_t CenterDuplicateMgr::getCharEnterArea(CharIDType charId)
{
	auto iter = m_charEnterArea.find(charId);
	return (iter != m_charEnterArea.end()) ? iter->second : 0;
}
//增加玩家进入之前所在的区域
void CenterDuplicateMgr::addCharEnterArea(CharIDType charId, uint32_t areaId)
{
	m_charEnterArea[charId] = areaId;
}
//删除玩家进入之前所在的区域
void CenterDuplicateMgr::delCharEnterArea(CharIDType charId)
{
	m_charEnterArea.erase(charId);
}

//获取等待副本数据
dupInfo *CenterDuplicateMgr::getWaitDuplicate(uint32_t sceneId)
{
	DupDataMap::iterator iter = m_mapWaitDupData.find(sceneId);
	return (iter != m_mapWaitDupData.end()) ? &iter->second : nullptr;
}

//获取等待创建副本数据
uint32_t CenterDuplicateMgr::getWaitCreate(CharIDType charId)
{
	auto iter = m_mapWaitCreate.find(charId);
	return (iter != m_mapWaitCreate.end()) ? iter->second : 0;
}
//增加玩家等待创建副本数据
void CenterDuplicateMgr::addWaitCreate(CharIDType charId, uint32_t sceneId)
{
	m_mapWaitCreate[charId] = sceneId;
}
//删除玩家等待创建副本数据
void CenterDuplicateMgr::delWaitCreate(CharIDType charId)
{
	m_mapWaitCreate.erase(charId);
}

//删除一个等待副本数据
void CenterDuplicateMgr::delWaitDuplicate(uint32_t sceneId,int32_t res /*= RET_SUCCESS*/)
{
	DupDataMap::iterator iter = m_mapWaitDupData.find(sceneId);
	if (iter != m_mapWaitDupData.end())
	{
		//
		dupInfo &stwait = iter->second;
		if (EDuplicateKeyType_Single == stwait.keyType 
			|| EDuplicateKeyType_Room == stwait.keyType 
			|| EDuplicateKeyType_Team == stwait.keyType
			|| EDuplicateKeyType_Arena == stwait.keyType
			|| EDuplicateKeyType_Compete == stwait.keyType
			)
		{
			delWaitCreate(stwait.cid);
		}
		else if (EDuplicateKeyType_Union == stwait.keyType)
		{
			delWaitCreateUnion((uint32_t)stwait.keyValue);
		}
		else if (EDuplicateKeyType_Pestilence == stwait.keyType)
		{
			if (RET_SUCCESS != res)  //失败，清空准备状态
			{
				int32_t queueId = stwait.keyValue;
				DupQueue *pQueue = getQueue(queueId);
				if (nullptr != pQueue)
				{
					pQueue->ClearReady();
				}
			}			
		}

		m_mapWaitDupData.erase(iter);
	}
	
}

dupInfo *CenterDuplicateMgr::createWaitDup(uint32_t dupId, int8_t dupType, uint32_t mapId, LogicToCenter_EnterDupReq &enterProto, bool notifyLogic)
{
	//
	dupInfo info;
	info.dupId = dupId;
	info.cid = enterProto.charid();
	info.keyType = (int8_t)enterProto.key_type();
	info.keyValue = enterProto.key_value();
	info.dupType = dupType;
	info.createTime = g_GetGlobalServerTime()->UnixSec();
	info.unionSceneType = enterProto.union_scene_type();
	//
	CreateSceneParamProto paramProto;
	paramProto.set_param_type(ESceneParamType_Dup);
	paramProto.set_char_id(info.cid);
	paramProto.set_duplicate_id(info.dupId);
	paramProto.set_key_type(info.keyType);
	paramProto.set_key_value(info.keyValue);
	paramProto.set_left_sec(enterProto.left_sec());
	paramProto.set_union_lev(enterProto.union_lev());
	paramProto.set_union_average_lev(enterProto.union_average_lev());
	paramProto.set_union_scene_type(enterProto.union_scene_type());
	//
	int32_t isize = enterProto.area_size();
	for (int32_t i = 0; i < isize; ++i)
	{
		const DupBeforAreaProto &proto = enterProto.area(i);
		addCharEnterArea(proto.charid(), proto.areaid());
		//
		DupBeforAreaProto *protoEx = paramProto.add_area();
		if (nullptr != protoEx)
		{
			protoEx->CopyFrom(proto);
		}
	}
	if (enterProto.has_mirror())
	{
		const CharacterMirrorData protoMirror = enterProto.mirror();
		CharacterMirrorData *protoMirrorEx = paramProto.mutable_mirror();
		if (nullptr == protoMirrorEx)
		{
			LogErrFmtPrint("[center] CenterDuplicateMgr::createWaitDup....nullptr == protoMirrorEx...charid:%lu, dupid:%u,duptype:%u , keytype:%d, keyvalue:%u,", info.cid,info.dupId,info.dupType,info.keyType,(uint32_t)info.keyValue);
			return nullptr;
		}
		protoMirrorEx->CopyFrom(protoMirror);
	}
	int32_t ibornSize = enterProto.char_born_size();
	for (int32_t j = 0; j < ibornSize; ++j)
	{
		const DupBornProto &protoBorn = enterProto.char_born(j);
		info.mapCharBorn[protoBorn.charid()] = protoBorn.bornid();
		//
		DupBornProto *protoBornParam = paramProto.add_born();
		if (nullptr != protoBornParam)
		{
			protoBornParam->CopyFrom(protoBorn);
		}
	}

	if (!g_GetCenterSceneMgr()->CenterCreateScene(mapId, info.sceneId, info.logicServerId,paramProto,notifyLogic))
	{
		return nullptr;
	}
	//LogDebugFmtPrint("[center] sceneid:%u ,dupid:%u, mapid:%u  ", info.sceneId,dupId,mapId);
	if (info.sceneId == 0 || info.logicServerId == 0)
	{
		return nullptr;
	}

	m_mapWaitDupData[info.sceneId] = info;
	//
	if (EDuplicateKeyType_Single == info.keyType 
		|| EDuplicateKeyType_Room == info.keyType 
		|| EDuplicateKeyType_Team == info.keyType
		|| EDuplicateKeyType_Arena == info.keyType
		|| EDuplicateKeyType_Compete == info.keyType
		)
	{
		addWaitCreate(info.cid, info.sceneId);
	}
	else if (EDuplicateKeyType_Union == info.keyType)
	{
		if (EUnionSceneType_Home != info.unionSceneType) //工会驻地不需要添加等待，其他的都是先创建副本，然后再通知进入副本
		{
			addWaitCreateUnion((uint32_t)info.keyValue, info.sceneId);
		}
	}

	return &m_mapWaitDupData[info.sceneId];
}
//能否进入工会驻地
int32_t CenterDuplicateMgr::canEnterUnionHomeDup(CharIDType charId, uint32_t sceneId)
{
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr == pdupInfo)
	{
		return RET_UNION_HOME_SCENE_NOT_EXIST;
	}
	if (!pdupInfo->isBegin || pdupInfo->isEnd)
	{
		return RET_UNION_HOME_SCENE_NOT_EXIST;
	}
	if (EUnionSceneType_Home != pdupInfo->unionSceneType)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::enterUnionHomeDup.....dupid:%u, sceneid:%u, keytype:%d, keyValue:%llu ,sceneType:%d, charid:%llu ", pdupInfo->dupId, sceneId, pdupInfo->keyType, pdupInfo->keyValue,pdupInfo->unionSceneType, charId);
		return RET_FAIL;
	}
	if (g_GetUnionMgr()->GetCharUnionId(charId) != pdupInfo->keyValue)
	{
		return RET_UNION_CAN_NOT_ENTER_HOME;
	}
	return  canEnterDup(charId, pdupInfo->dupId, pdupInfo->keyType, pdupInfo->keyValue, pdupInfo->unionSceneType);
}

//能否进入工会地宫
int32_t CenterDuplicateMgr::canEnterUnionDungeon(CharIDType charId)
{
	uint32_t unionId = g_GetUnionMgr()->GetCharUnionId(charId);
	uint32_t sceneId = g_GetUnionMgr()->GetSceneIdByType(unionId, EUnionSceneType_DunGeon);
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr == pdupInfo)
	{
		return RET_UNION_DUNGEON_SCENE_NOT_EXIST;
	}
	if (!pdupInfo->isBegin || pdupInfo->isEnd)
	{
		return RET_UNION_DUNGEON_SCENE_NOT_EXIST;
	}
	if (EUnionSceneType_DunGeon != pdupInfo->unionSceneType)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::canEnterUnionDungeon.....dupid:%u, sceneid:%u, keytype:%d, keyValue:%llu ,sceneType:%d, charid:%llu ", pdupInfo->dupId, sceneId, pdupInfo->keyType, pdupInfo->keyValue, pdupInfo->unionSceneType, charId);
		return RET_FAIL;
	}
	if (unionId != (uint32_t)pdupInfo->keyValue)
	{
		return RET_UNION_CAN_NOT_ENTER_DUNGEON;
	}
	return  canEnterDup(charId, pdupInfo->dupId, pdupInfo->keyType, pdupInfo->keyValue, pdupInfo->unionSceneType);
}

//进入工会相关副本景
int32_t CenterDuplicateMgr::enterUnionSceneDup(SUnionSceneParam &param)
{
	uint32_t sceneId = g_GetUnionMgr()->GetSceneIdByType(param.unionId,param.sceneType);
	dupInfo *pdupInfo = getDuplicate(sceneId);
	if (nullptr == pdupInfo) //副本不存在
	{
		if (EUnionSceneType_Home == param.sceneType) //工会驻地是一开始就创建好了的
		{
			return RET_UNION_HOME_SCENE_NOT_EXIST;
		}
		else
		{
			//其他的类型，副本不存在，需要创建
			LogicToCenter_EnterDupReq reqEnter;
			reqEnter.set_charid(param.charId);
			reqEnter.set_duplicate_id(param.dupId); //这里的副本ID需要外部传进来，可能一个sceneType对应多个副本
			reqEnter.set_key_type(EDuplicateKeyType_Union);
			reqEnter.set_key_value(param.unionId);
			reqEnter.set_left_sec(param.leftSec);
			reqEnter.set_union_scene_type(param.sceneType);
			CUnion *pUnion = g_GetUnionMgr()->GetUnion(param.unionId);
			if (nullptr != pUnion)
			{
				reqEnter.set_union_average_lev(pUnion->EliteAverageLev());
			}
			//
			uint32_t dupSceneId = 0;
			return enterDupReq(reqEnter,dupSceneId);
		}
	}
	else if (!pdupInfo->isBegin || pdupInfo->isEnd) //还没开始，或者已经结束
	{
		return RET_UNION_HOME_SCENE_NOT_EXIST;
	}

	//副本已存在，并且没有结束，直接通知进入副本
	if (!notifyEnterDup(sceneId, param.charId))
	{
		return RET_FAIL;
	}

	return RET_SUCCESS;
}

//进入工会地宫
int32_t CenterDuplicateMgr::enterUnionDungeon(CharIDType charId)
{
	SUnionSceneParam param;
	param.charId = charId;
	param.dupId = g_GetDuplicateCfgMgr()->GetUnionDunGeonDupId();
	param.sceneType = EUnionSceneType_DunGeon;
	param.unionId = g_GetUnionMgr()->GetCharUnionId(charId);
	return enterUnionSceneDup(param);
}

//创建工会驻地副本
int32_t CenterDuplicateMgr::createUnionHomeDup(uint32_t unionId, int32_t lev)
{
	uint32_t unionHomeDupId = g_GetDuplicateCfgMgr()->GetUnionHomeDupId();
	LogicToCenter_EnterDupReq req;
	req.set_charid(0);
	req.set_duplicate_id(unionHomeDupId);
	req.set_key_type((int32_t)EDuplicateKeyType_Union);
	req.set_key_value(unionId);
	req.set_union_lev(lev);
	req.set_union_scene_type(EUnionSceneType_Home);
	uint32_t dupSceneId = 0;
	return enterDupReq(req,dupSceneId);
}

//进入新手引导副本
dupInfo * CenterDuplicateMgr::enterGuideDup(CharIDType charId, uint32_t dupId)
{
	//进入新手引导副本之前，如果有等待创建副本的返回，需要先清掉等待信息
	//删除等待创建数据，当作创建副本失败来处理
	dupWaitRet *pdupWaitRet = getDupWaitRet(charId);
	if (nullptr != pdupWaitRet)
	{
		g_GetCenterDuplicateMgr()->delWaitDuplicate(pdupWaitRet->sceneId, RET_FAIL);
	}
	//
	LogicToCenter_EnterDupReq req;
	req.set_charid(charId);
	req.set_duplicate_id(dupId);
	req.set_key_type((int32_t)EDuplicateKeyType_Single);
	req.set_key_value(charId);
	uint32_t dupSceneId = 0;
	int32_t ret = enterDupReq(req,dupSceneId,false);
	if (RET_SUCCESS != ret)
	{
		return nullptr;
	}
	return getWaitDuplicate(dupSceneId);
}

//进入竞技场
int32_t CenterDuplicateMgr::enterArenaDup(CharIDType charId, const CharacterMirrorData &mirrorData)
{
	uint32_t arenaDupId = g_GetDuplicateCfgMgr()->GetArenaDupId();
	LogicToCenter_EnterDupReq req;
	req.set_charid(charId);
	req.set_duplicate_id(arenaDupId);
	req.set_key_type((int32_t)EDuplicateKeyType_Arena);
	req.set_key_value(charId);
	CharacterMirrorData *protoMirror = req.mutable_mirror();
	if (nullptr == protoMirror)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::enterArenaDup....nullptr == protoMirror...charid:%lu ",charId);
		return RET_FAIL;
	}
	protoMirror->CopyFrom(mirrorData);
	uint32_t dupSceneId = 0;
	return enterDupReq(req,dupSceneId);
}

//进入挑战阵营首领副本
int32_t CenterDuplicateMgr::enterCampDup(CharIDType charId, const CharacterMirrorData &mirrorData)
{
	uint32_t campDupId = g_GetDuplicateCfgMgr()->GetCampDupId();
	LogicToCenter_EnterDupReq req;
	req.set_charid(charId);
	req.set_duplicate_id(campDupId);
	req.set_key_type((int32_t)EDuplicateKeyType_Arena);
	req.set_key_value(charId);
	CharacterMirrorData *protoMirror = req.mutable_mirror();
	if (nullptr == protoMirror)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::enterCampDup....nullptr == protoMirror...charid:%lu ", charId);
		return RET_FAIL;
	}
	protoMirror->CopyFrom(mirrorData);
	uint32_t dupSceneId = 0;
	return enterDupReq(req,dupSceneId);
}

//进入切磋副本
int32_t CenterDuplicateMgr::enterCompete(CharIDType charId, CharIDType dstId)
{
	uint32_t competeDupId = g_GetDuplicateCfgMgr()->GetCompeteDupId();
	const DuplicateDuplicateCfgInfo *pCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(competeDupId);

	
	if (nullptr == pCfg)
	{
		return RET_CONFIG_ERROR;
	}
/*
	const std::vector<BornRefLocation> *pVecBorn = g_GetMapLocationCfg()->GetMapBornLocation(pCfg->sceneResource);
	if (nullptr == pVecBorn || pVecBorn->size() < 2)
	{
		return RET_CONFIG_ERROR;
	}*/
	
	const VecBornPosCfg *pVecBorn = g_GetMapCfgMgr()->GetBornCfgByMap(pCfg->sceneResource);
	if (nullptr == pVecBorn || pVecBorn->size() < 2)
	{
		return RET_CONFIG_ERROR;
	}

	LogicToCenter_EnterDupReq req;

	//切磋分配双方出生点
	DupBornProto *protoBornA = req.add_char_born();
	DupBornProto *protoBornB = req.add_char_born();
	if (nullptr == protoBornA || nullptr == protoBornB)
	{
		return RET_FAIL;
	}

	protoBornA->set_charid(charId);
	protoBornA->set_bornid(0);
	protoBornB->set_charid(dstId);
	protoBornB->set_bornid(1);

	req.set_charid(charId);
	req.set_duplicate_id(competeDupId);
	req.set_key_type((int32_t)EDuplicateKeyType_Compete);
	req.set_key_value(dstId);
	uint32_t dupSceneId = 0;
	return enterDupReq(req,dupSceneId);
}

//进入副本
int32_t CenterDuplicateMgr::enterDupReq(LogicToCenter_EnterDupReq &enterProto,uint32_t &dupSceneId, bool notifyLogic /*= true*/)
{
	CharIDType charId = enterProto.charid();
	uint32_t dupId = enterProto.duplicate_id();
	int8_t keytype = enterProto.key_type();
	uint64_t keyValue = enterProto.key_value();
	int8_t sceneType = enterProto.union_scene_type();
	const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
	if (nullptr == pcfg)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::enterDupReq....nullptr == pcfg...charid:%lu, dupid:%u,   keytype:%d, keyvalue:%u  ", charId, dupId, keytype, (uint32_t)keyValue);
		return RET_DUPLICATE_NOT_EXISTS;
	}

	int32_t ret = canEnterDup(charId, dupId, keytype, keyValue, sceneType);
	if (RET_SUCCESS != ret)
	{
		return ret;
	}
	//单人的话直接请求创建场景
	dupInfo *pdupInfo = createWaitDup(dupId, (int8_t)pcfg->duplicateType, pcfg->sceneResource, enterProto,notifyLogic);
	if (nullptr == pdupInfo)
	{
		return RET_FAIL;
	}
	//
	ret =  enterDupExReq(pdupInfo);
	if (RET_SUCCESS == ret)
	{
		dupSceneId = pdupInfo->sceneId;
	}
	return ret;
}
//进入副本扩展处理
int32_t CenterDuplicateMgr::enterDupExReq(dupInfo *pdupInfo)
{
	if (nullptr == pdupInfo)
	{
		return RET_FAIL;
	}
	int32_t ret = RET_SUCCESS;
	int8_t keytype = pdupInfo->keyType;
	//修改房间状态
	if (EDuplicateKeyType_Room == keytype)
	{
		//修改房间状态
		if (nullptr != g_GetRoomMgr()->startFight((uint32_t)pdupInfo->keyValue, pdupInfo->sceneId))
		{

			//成功，等待进副本，这里直接返回
			ret = RET_SUCCESS;
		}
		else
		{
			ret = RET_FAIL;
			//失败，重置状态
			g_GetRoomMgr()->resetState((uint32_t)pdupInfo->keyValue);

			LogErrFmtPrint("[center] CenterDuplicateMgr::enterDupReq....startFight failed....charid:%lu, dupid:%u, sceneid:%u,  keytype:%d, keyvalue:%u  ", pdupInfo->cid, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, (uint32_t)pdupInfo->keyValue);
		}
	}
	else if (EDuplicateKeyType_Team == keytype)
	{
		DupTeamState *pTeamState = getDupTeamState((uint32_t)pdupInfo->keyValue);
		if (nullptr != pTeamState)
		{
			pTeamState->startCreate();//开始创建副本
			ret = RET_SUCCESS;
		}
		else
		{
			LogErrFmtPrint("[center] CenterDuplicateMgr::enterDupReq....nullptr == pTeamState, charid:%lu, dupid:%u, sceneid:%u,  keytype:%d, keyvalue:%u  ", pdupInfo->cid, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, (uint32_t)pdupInfo->keyValue);
			//失败
			ret = RET_FAIL;
		}
	}
	else if (EDuplicateKeyType_Pestilence == keytype)
	{
		DupQueue *pQueue = getQueue((int32_t)pdupInfo->keyValue);
		if (nullptr != pQueue)
		{
			pQueue->Ready();	//队列准备进副本
			ret = RET_SUCCESS;
		}
		else
		{
			LogErrFmtPrint("[center] CenterDuplicateMgr::enterDupReq....nullptr == pQueue, charid:%lu, dupid:%u, sceneid:%u,  keytype:%d, keyvalue:%u  ", pdupInfo->cid, pdupInfo->dupId, pdupInfo->sceneId, pdupInfo->keyType, (uint32_t)pdupInfo->keyValue);
			//失败
			ret = RET_FAIL;
		}
	}
	return ret;
}

//玩家是否在副本中
bool CenterDuplicateMgr::isCharInDup(CharIDType charId)
{
	if (getWaitCreate(charId) > 0)
	{
		return true;
	}
	else if (getDupWaitRet(charId) != nullptr)
	{
		return true;
	}
	else
	{
		uint32_t sceneId = getDupChar(charId);
		dupInfo *pdupInfo = getDuplicate(sceneId);
		if (nullptr != pdupInfo)
		{
			if (EUnionSceneType_Home != pdupInfo->unionSceneType
				&& EUnionSceneType_DunGeon != pdupInfo->unionSceneType
				) //工会场景和地宫场景 要过滤掉，不能算作副本
			{
				return true;
			}
		}
	}

	return false;
}
//通知玩家进副本失败
void CenterDuplicateMgr::notifyEnterFailed(CharIDType charId,uint32_t duplId, int32_t retcode)
{
	Duplicate_EnterRsp rsp;
	rsp.set_retcode(retcode);
	rsp.set_duplicate_id(duplId);
	g_GetCenterService()->SendDataToClient(charId,EMODULE_ID_DUPLICATE, LOGIC_TO_CLIENT_DUPLICATE_ENTER, &rsp);
}
//能否进副本
int32_t CenterDuplicateMgr::canEnterDup(CharIDType charId, uint32_t dupId, int8_t keyType, uint64_t keyValue,int8_t unionSceneType/* = EUnionSceneType_None*/)
{
	_UNUSE(dupId);
	if (EDuplicateKeyType_Single == keyType)
	{
		if (charId != keyValue)
		{
			return RET_DUPLICATE_CAN_NOT_ENTER;
		}
		uint32_t sceneId = getDupChar(charId);
		dupInfo *pdupInfo = getDuplicate(sceneId);
		if (nullptr != pdupInfo) //在副本里面但是副本还没结束或者结束了但是没有通关，是不行允许在进入另一个副本的
		{
			if (!pdupInfo->isEnd || RET_SUCCESS != pdupInfo->res) //主要针对从一个副本 进入另一个副本，目前只有天梯副本有需求
			{
				return RET_DUPLICATE_CAN_NOT_ENTER;
			}			
		}
		if (isCharInDup(charId))
		{
			return RET_DUPLICATE_CAN_NOT_ENTER;
		}

		if (g_GetRoomMgr()->getCharRoom(charId) > 0)
		{
			return RET_ROOM_ALREADY_JOIN;
		}
		//这里增加组队判断，有队伍时不允许进入
		if (g_GetTeamMgr()->GetTeamId(charId) > 0)
		{
			return RET_TEAM_ALREADY_JOIN;
		}
		if (inQueue(charId))
		{
			//在排队中
			return RET_DUPLICATE_ALREADY_IN_QUEUE;
		}
	}
	else if (EDuplicateKeyType_Room == keyType)
	{
		uint32_t roomId = g_GetRoomMgr()->getCharRoom(charId);
		if (roomId != (uint32_t)keyValue)
		{
			return RET_DUPLICATE_NOT_IN_ROOM;
		}
		return g_GetRoomMgr()->canStartFight(charId,roomId);
	}
	else if (EDuplicateKeyType_Team == keyType)
	{
		uint32_t teamId = (uint32_t)keyValue;
		Team *pTeam = g_GetTeamMgr()->FindTeamById(teamId);
		if (nullptr == pTeam)
		{
			return RET_TEAM_NO_EXIST;
		}
		if (!pTeam->IsLeader(charId))
		{
			return RET_DUPLICATE_NOT_TEM_LEADER;
		}
		DupTeamState *pState = getDupTeamState(teamId);
		if (nullptr == pState)
		{
			return RET_DUPLICATE_CAN_NOT_ENTER;
		}
		//校验队员是否在线
		SET_UINT64 setMember;
		setMember.clear();
		pTeam->GetMemeberList(setMember);
		SET_UINT64::iterator iterMem = setMember.begin();
		for (; iterMem != setMember.end(); ++iterMem)
		{
			CharIDType memCharId = (*iterMem);
			ActiveCharacter *pOnlineChar = g_GetActiveCharacterMgr()->GetOnlineCharacter(memCharId);
			if (nullptr == pOnlineChar)
			{
				//不在线
				return RET_DUPLICATE_TEAM_MEM_NOT_ONLINE;
			}
			else if (EDupTeamCharState_Agree != pState->getState(memCharId))
			{
				return RET_DUPLICATE_TEAM_MEM_NOT_AGREE;
			}
			else if (isCharInDup(memCharId))
			{
				return RET_DUPLICATE_TEAM_MEM_ALREADY_IN;
			}
			else if (inQueue(memCharId))
			{
				//在排队中
				return RET_DUPLICATE_ALREADY_IN_QUEUE;
			}
			else if (g_GetActivityMgr()->InSonOfKillingStatus(memCharId))
			{
				return RET_DUPLICATE_TEAM_MEM_IN_SONOFKILL;
			}
		}
	}
	else if (EDuplicateKeyType_Arena == keyType)
	{
		if (charId != keyValue)
		{
			return RET_DUPLICATE_CAN_NOT_ENTER;
		}
		else if (isCharInDup(charId))
		{
			return RET_DUPLICATE_ALREAY_IN;
		}
		else if (g_GetRoomMgr()->getCharRoom(charId) > 0)
		{
			return RET_ROOM_ALREADY_JOIN;
		}
		else if (g_GetTeamMgr()->GetTeamId(charId) > 0)
		{
			return RET_TEAM_ALREADY_JOIN;
		}
		else if (inQueue(charId))
		{
			//在排队中
			return RET_DUPLICATE_ALREADY_IN_QUEUE;
		}
	}
	else if (EDuplicateKeyType_Pestilence == keyType)
	{
		int32_t queueId = keyValue;
		DupQueue *pQueue = getQueue(queueId);
		if (nullptr == pQueue)
		{
			return RET_DUPLICATE_CAN_NOT_ENTER;
		}
		if (!pQueue->IsFull() || !pQueue->IsAllOnline())
		{
			//队列未满，不能进副本
			return RET_DUPLICATE_CAN_NOT_ENTER;
		}
	}
	else if (EDuplicateKeyType_Union == keyType)
	{
		uint32_t unionId = (uint32_t)keyValue;
		bool bcheck = true;
		if (EUnionSceneType_Home == unionSceneType)
		{
			if (charId <= 0)//小于0的时候是创建工会相关的场景，不用检查，大于0的时候时玩家进入工会相关的场景，是需要检查的
			{
				bcheck = false;
			}
		}
		if (bcheck)
		{
			if (isCharInDup(charId) > 0)
			{
				return RET_DUPLICATE_ALREAY_IN;
			}
			else if (g_GetUnionMgr()->GetCharUnionId(charId) != unionId)
			{
				return RET_UNION_NOT_JOIN;
			}
			else if (getWaitCreateUnion(unionId) > 0)
			{
				return RET_DUPLICATE_CAN_NOT_ENTER;
			}
		}
	}
	else if (EDuplicateKeyType_Compete == keyType)
	{
		if (isCharInDup(charId) || isCharInDup(keyValue))
		{
			return RET_DUPLICATE_ALREAY_IN;
		}
		if (g_GetRoomMgr()->getCharRoom(charId) || g_GetRoomMgr()->getCharRoom(keyValue))
		{
			return RET_ROOM_ALREADY_JOIN;
		}
		if (inQueue(charId) || inQueue(keyValue))
		{
			return RET_DUPLICATE_ALREADY_IN_QUEUE;
		}
	}
	else
	{
		return RET_DUPLICATE_CAN_NOT_ENTER;
	}

	//可以添加更多的条件判断


	return RET_SUCCESS;
}

//能否进入竞技场副本
int32_t CenterDuplicateMgr::canEnterArenaDup(CharIDType charId)
{
	uint32_t arenaDupId = g_GetDuplicateCfgMgr()->GetArenaDupId();
	const DuplicateDuplicateCfgInfo *pDupCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(arenaDupId);
	if (nullptr == pDupCfg)
	{
		LogErrFmtPrint("[center] CenterDuplicateMgr::canEnterArenaDup.....nullptr == pDupCfg...arenaDupId:%u ", arenaDupId);
		return RET_FAIL;
	}
	return canEnterDup(charId, arenaDupId, (int8_t)EDuplicateKeyType_Arena, charId);
}

//获取新手引导步骤配置
const GuideStepCfgInfo *CenterDuplicateMgr::GetGuideStepCfg(uint32_t race, uint32_t step)
{
	VecGuideRaceCfg::iterator iter = m_vecGuideCfg.begin();
	for (; iter != m_vecGuideCfg.end(); ++iter)
	{
		GuidRaceCfgInfo &info = (*iter);
		if (info.nRace == race)
		{
			GuideStepCfgMap::iterator iterStep = info.mapStep.find(step);
			return (iterStep != info.mapStep.end()) ? &iterStep->second : nullptr;
		}
	}
	return nullptr;
}
//最大步骤
uint32_t CenterDuplicateMgr::GetGuideMaxStep()
{
	return (uint32_t)m_vecGuideCfg.size();
}
//加载新手引导步骤配置
bool CenterDuplicateMgr::LoadGuideStepCfg()
{
	LuaScript *pScript = g_GetCSScriptMgr()->GetScript();
	if (nullptr == pScript)
	{
		LogErrFmtPrint("[logic] CenterDuplicateMgr::LoadGuideStepCfg....nullptr == pScript... ");
		return false;
	}
	luabridge::LuaRef ref(pScript->GetState());
	if (!pScript->CallTableFuncRet("Duplicate", "LuaNewGuideStep", ref))
	{
		LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...pScript->CallTableFuncRet failed....");
		return false;
	}
	if (ref.isNil())
	{
		LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...ref.isNil....");
		return false;
	}
	if (!ref.isTable())
	{
		LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...ref.isTable() return false....");
		return false;
	}
	int32_t cfglen = ref.length();
	if (cfglen <= 0)
	{
		LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...cfglen <= 0....");
		return false;
	}
	for (int32_t i = 1; i <= cfglen; ++i)
	{
		LuaRef refGuide = ref[i];
		if (!refGuide.isTable())
		{
			LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...!refGuide.isTable()....i:%d ",i);
			return false;
		}
		if (!refGuide["race"].isNumber()
			|| !refGuide["dup"].isNumber()
			|| !refGuide["step"].isTable()
			)
		{
			LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...cfg type error....i:%d ", i);
			return false;
		}

		uint32_t race = refGuide["race"].cast<uint32_t>();
		uint32_t dupId = refGuide["dup"].cast<uint32_t>();
		//校验是否重复
		VecGuideRaceCfg::iterator iterRace = m_vecGuideCfg.begin();
		for (; iterRace != m_vecGuideCfg.end(); ++iterRace)
		{
			GuidRaceCfgInfo &raceInfo = (*iterRace);
			if (raceInfo.nRace == race)
			{
				LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...repeated race....i:%d,race:%u ", i,race);
				return false;
			}
		}
		//
		GuidRaceCfgInfo info;
		info.nRace = race;
		//校验
		if (!ERace_IsValid(race))
		{
			LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...race error....i:%d,race:%u ", i,race);
			return false;
		}
		const DuplicateDuplicateCfgInfo *pDupCfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
		if (nullptr == pDupCfg)
		{
			LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...nullptr == pDupCfg....i:%d,race:%u,dupid:%u ", i, race,dupId);
			return false;
		}
		//步骤
		LuaRef refStep = refGuide["step"];
		int32_t steplen = refStep.length();
		if (steplen <= 0)
		{
			LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...steplen <= 0....i:%d,race:%u,dupid:%u ", i, race, dupId);
			return false;
		}
		for (int32_t j = 1; j <= steplen; ++j)
		{
			LuaRef refSub = refStep[j];
			if (!refSub.isTable())
			{
				LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...!refSub.isTable()....i:%d,race:%u,dupid:%u,j:%d ", i, race, dupId,j);
				return false;
			}
			if (refSub.length() != 2)
			{
				LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...refSub.length() != 2....i:%d,race:%u,dupid:%u,j:%d ", i, race, dupId, j);
				return false;
			}
			uint32_t bornId = refSub[1].cast<uint32_t>();
			uint32_t missionId = refSub[2].cast<uint32_t>();
			//
			const TeleportBornCfgInfo *pBornCfg = g_GetTeleportBornCfgTable()->GetTeleportBornCfgInfo(bornId);
			if (nullptr == pBornCfg)
			{
				LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...nullptr == pBornCfg....i:%d,race:%u,dupid:%u,j:%d,bornId:%u ", i, race, dupId, j, bornId);
				return false;
			}
			if (pBornCfg->scene != pDupCfg->sceneResource)
			{
				LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...pBornCfg->scene != pDupCfg->sceneResource...i:%d,race:%u,dupid:%u,j:%d,bornId:%u,bornScene:%u,dupScene:%u ", i, race, dupId, j, bornId,pBornCfg->scene,pDupCfg->sceneResource);
				return false;
			}
			const SBornPosCfgInfo *pBornPosCfg = g_GetMapCfgMgr()->GetBornCfgInfo(pBornCfg->scene, bornId);
			if (nullptr == pBornPosCfg)
			{
				LogErrFmtPrint("CenterDuplicateMgr::LoadGuideStepCfg...nullptr == pBornPosCfg...i:%d,race:%u,dupid:%u,j:%d,bornId:%u,bornScene:%u, ", i, race, dupId, j, bornId, pBornCfg->scene);
				return false;
			}
			GuideStepCfgInfo stepInfo;
			stepInfo.nStep = j;
			stepInfo.bornId = bornId;
			stepInfo.missionId = missionId;
			stepInfo.nDupId = dupId;
			//
			info.mapStep[stepInfo.nStep] = stepInfo;
		}
		m_vecGuideCfg.push_back(info);
	}

	return true;
}